home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 431_01 / rserver.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-06  |  22.4 KB  |  931 lines

  1. /*
  2.   SERVER
  3.     1. wait for request packets
  4.     2. execute request packet
  5.     3. package result
  6.     4. continue
  7.  
  8.   notes:
  9.      each function is in C but calls DOS through intr().
  10.      this is clunky, i know, but it comes from a bizarre design. initially
  11.      i thought i could translate everything into C calls (open, close, etc..)
  12.      but no such luck because i had to translate the C return codes to DOS
  13.      codes which was much too much trouble. later, it turns out the that
  14.      _doserrno holds the DOS return code, but i had already re-worked
  15.      my code.
  16.  
  17.      this is almost entirely CLIENT controlled. the server makes few
  18.      decisions. all filenames are translated at the client, etc...
  19. */
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <dos.h>
  23. #include <dir.h>
  24. #include <string.h>
  25. #include <assert.h>
  26. #include <io.h>
  27. #include <fcntl.h>
  28. #include <sys\stat.h>
  29. #include <errno.h>
  30. #include <conio.h>
  31. #include <time.h>
  32.  
  33. #include "ifs.h"
  34. #include "comio.h"
  35. #include "crc32.h"
  36. #include "svr0.h"
  37. #include "myalloc.h"
  38. #include "rifs.h"
  39.  
  40. #include "rclient.h"
  41. #include "local.h"
  42. unsigned _stklen = 512;      /* minimal local stack */
  43.  
  44. BYTE    *SDA;           /* swappable data area         */
  45. WORD     SDA_maxsize;   /* size of SDA                 */
  46. WORD     SDA_minsize;   /* min. size of SDA            */
  47. BYTE    *SDA_DOSBUSY;   /* DOS busy flag               */
  48. BYTE    *CDS_base;      /* current directory structure */
  49. WORD     CDS_EntrySize; /* # of bytes per entry        */
  50. WORD     CDS_ct;        /* number of entries           */
  51. WORD     CDS_TotalSize; /* total number of bytes       */
  52.  
  53. /*************************************************************************
  54.  *************************************************************************
  55.   SERVER
  56.  *************************************************************************
  57.  *************************************************************************/
  58. XMITBUF *iobuf;    /* send / recieve buffer(s)    */
  59. XMITBUF *iobufptr; /* pointer to recieve buffer */
  60.  
  61. BYTE *lcl_SDA;  /* local copy of SDA    */
  62. CDS  *lcl_CDS;  /* local copy of CDS    */
  63.  
  64. LOCAL int   datasize = BLOCKSIZE; /* size of packet data  */
  65.  
  66. LOCAL int   state;    /*
  67.                           used by ASYNC for state info:
  68.                           0 = looking for 'K'
  69.                           1 = looking for 'Y'
  70.                           2 = storing ALL incoming
  71.                           3 = waiting to finish server request
  72.                        */
  73. LOCAL IFS_STAT IFS_stat; /* struct for keeping statistics */
  74.  
  75. BOOL background=TRUE; /* TRUE if running in background, else FALSE */
  76.  
  77. LOCAL unsigned openpsp[MAXOPEN];
  78.  
  79. #define SETRESULT(a) {iobufptr->length=0; iobufptr->cmd=a;}
  80.  
  81. /*
  82.   remove directory
  83.     ASCIIz = name of directory to remove
  84. */
  85. LOCAL void svr_rmdir(XMITBUF *iobuf)
  86. {
  87.   if (rmdir(iobuf->data)) {
  88.     SETRESULT(_doserrno);
  89.   } else
  90.     SETRESULT(0);
  91. }
  92.  
  93. /*
  94.   make directory
  95.     ASCIIz = name of directory to create
  96. */
  97. LOCAL void svr_mkdir(XMITBUF *iobuf)
  98. {
  99.   if (mkdir(iobuf->data)) {
  100.     SETRESULT(_doserrno);
  101.   } else
  102.     SETRESULT(0);
  103. }
  104. /*
  105.   change directory
  106.     ASCIIz = name of directory to change
  107. */
  108. LOCAL void svr_chdir(XMITBUF *iobuf)
  109. {
  110.   if (chdir(iobuf->data)) {
  111.     SETRESULT(_doserrno);
  112.   } else
  113.     SETRESULT(0);
  114. }
  115.  
  116. /*
  117.   close file
  118.     WORD : handle of file to close
  119. */
  120. LOCAL void svr_closefile(XMITBUF *iobuf)
  121. {
  122.   unsigned cascade_error;
  123.   int handle = *(unsigned *) iobuf->data;
  124.  
  125.   if (setftime(handle, (struct ftime *) (iobuf->data+2)))
  126.     cascade_error = _doserrno;
  127.   else
  128.     cascade_error = 0;
  129.  
  130.   if (close(handle)) {
  131.     SETRESULT(_doserrno);
  132.   } else
  133.     SETRESULT(cascade_error);
  134.  
  135.   if (handle < MAXOPEN)
  136.     openpsp[handle]=0;
  137. }
  138.  
  139. /*
  140.   commit file buffers
  141.     WORD : handle of file to commit
  142. */
  143. LOCAL void svr_commitfile(XMITBUF *iobuf)
  144. {
  145.   SETRESULT(0);
  146. }
  147.  
  148. /*
  149.   read from a file
  150.     WORD  : handle
  151.     DWORD : position
  152.     WORD  : length
  153.   returns
  154.     WORD   : number of bytes read
  155.     BYTE[] : bytes
  156. */
  157. LOCAL void svr_readfile(XMITBUF *iobuf)
  158. {
  159.   int  handle=*(int *) iobuf->data;
  160.   long pos=   *(long *) (iobuf->data+2);
  161.   int  len=   *(int *) (iobuf->data+6);
  162.   int  rlen;
  163.  
  164.   lseek(handle, pos, SEEK_SET);
  165.   errno = 0;
  166.   _doserrno = 0;
  167.   rlen = read(handle, iobuf->data+2, len);
  168.   if (rlen != len) {
  169.     SETRESULT(_doserrno);
  170.   } else
  171.     SETRESULT(0);
  172.   *(int *) iobuf->data=rlen;
  173.   iobuf->length=2+rlen;
  174. }
  175.  
  176. /*
  177.   write to file
  178.     WORD    : file handle
  179.     DWORD   : position
  180.     WORD    : length
  181.     BYTES[] : data
  182.   return
  183.     WORD    : bytes written, 0xffff = error
  184. */
  185. LOCAL void svr_writefile(XMITBUF *iobuf)
  186. {
  187.   int  handle=*(int *) iobuf->data;
  188.   long pos=   *(long *) (iobuf->data+2);
  189.   int  len=   *(int *) (iobuf->data+6);
  190.   int wlen;
  191.  
  192.   lseek(handle, pos, SEEK_SET);
  193.   errno    = 0;
  194.   _doserrno = 0;
  195.   wlen = write(handle, iobuf->data+8, len);
  196.   if (wlen != len) {
  197.     SETRESULT(_doserrno);
  198.   } else
  199.     SETRESULT(0);
  200.   *(int *) iobuf->data=wlen;
  201.   iobuf->length=2;
  202. }
  203.  
  204. /*
  205.   lock file bytes
  206.     WORD  : handle
  207.     DWORD : position
  208.     DWORD : length
  209. */
  210. LOCAL void svr_lockfile(XMITBUF *iobuf)
  211. {
  212.   int handle=*(int *) iobuf->data;
  213.   long pos = *(long *) (iobuf->data + 2);
  214.   long len = *(long *) (iobuf->data + 6);
  215.  
  216.   if (lock(handle, pos, len)) {
  217.     SETRESULT(_doserrno);
  218.   } else
  219.     SETRESULT(0);
  220. }
  221.  
  222. /*
  223.   lock/unlock file bytes
  224.     WORD  : handle
  225.     WORD  : function (0 = lock / 1 = unlock)
  226.     DWORD : position
  227.     DWORD : size
  228. */
  229. LOCAL void svr_unlockfile(XMITBUF *iobuf)
  230. {
  231.   int handle=*(int *)   iobuf->data;
  232.   int fn    =*(int *)  (iobuf->data + 2);
  233.   long pos = *(long *) (iobuf->data + 4);
  234.   long len = *(long *) (iobuf->data + 8);
  235.   int  result;
  236.  
  237.   result = (fn) ? lock(handle, pos, len) : unlock(handle, pos, len);
  238.   if (result) {
  239.     SETRESULT(_doserrno);
  240.   } else
  241.     SETRESULT(0);
  242. }
  243.  
  244. /*
  245.   get free space
  246.     BYTE : drive number (0 = a)
  247.   return
  248.     struct dfree
  249. */
  250. LOCAL void svr_getspace(XMITBUF *iobuf)
  251. {
  252.   struct dfree *df=(void *) iobuf->data;
  253.   getdfree(iobuf->data[0], df);
  254.   if (df->df_sclus == 0xffff) {
  255.     SETRESULT(_doserrno);
  256.   } else {
  257.     SETRESULT(0);
  258.   }
  259.   iobuf->length = sizeof(*df);
  260. }
  261.  
  262. /*
  263.   set file attribute
  264.     WORD   : attribute
  265.     ASCIIz : filename
  266. */
  267. LOCAL void svr_setattr(XMITBUF *iobuf)
  268. {
  269.   if (chmod(iobuf->data+2, *(int *) iobuf->data)) {
  270.     SETRESULT(_doserrno);
  271.   } else
  272.     SETRESULT(0);
  273. }
  274.  
  275. /*
  276.   return file attribute
  277.     ASCIIz : filename
  278.   return
  279.     WORD   : attribute
  280. */
  281. LOCAL void svr_getattr(XMITBUF *iobuf)
  282. {
  283.   struct REGPACK regs;
  284.  
  285.   regs.r_ax=0x4300;
  286.   regs.r_dx=FP_OFF(iobuf->data);
  287.   regs.r_ds=FP_SEG(iobuf->data);
  288.   intr(0x21, ®s);
  289.   if (regs.r_flags & 0x01) {
  290.     SETRESULT(regs.r_ax);
  291.   } else {
  292.     SETRESULT(0);
  293.     *(int *) iobuf->data=regs.r_cx;
  294.     iobuf->length=2;
  295.   }
  296. }
  297.  
  298. /*
  299.   rename file
  300.     ASCIIz : old name
  301.     ASCIIz : new name
  302. */
  303. LOCAL void svr_renamefile(XMITBUF *iobuf)
  304. {
  305.   if (rename(iobuf->data, iobuf->data+strlen(iobuf->data)+1)) {
  306.     SETRESULT(_doserrno);
  307.   } else
  308.     SETRESULT(0);
  309. }
  310.  
  311. /*
  312.   delete file
  313.     ASCIIz : filename
  314. */
  315. LOCAL void svr_deletefile(XMITBUF *iobuf)
  316. {
  317.   if (unlink(iobuf->data)) {
  318.     SETRESULT(_doserrno);
  319.   } else
  320.     SETRESULT(0);
  321. }
  322.  
  323. /*
  324.   open file
  325.     WORD   : open mode
  326.     ASCIIz : filename
  327.   return
  328.     WORD   : file handle
  329.     WORD   : file attribute
  330.     WORD   : file time
  331.     WORD   : file date
  332.     DWORD  : file length
  333. */
  334. LOCAL void svr_openfile(XMITBUF *iobuf)
  335. {
  336.   struct REGPACK regs;
  337.   /*
  338.     call DOS open
  339.   */
  340.   regs.r_ax=0x3d00 | ((*(int *) iobuf->data) & 0xff);
  341.   regs.r_dx=FP_OFF(iobuf->data)+2;
  342.   regs.r_ds=FP_SEG(iobuf->data);
  343.   intr(0x21, ®s);
  344.   if (regs.r_flags & 0x01) {
  345.     SETRESULT(regs.r_ax);
  346.   } else {
  347.     SETRESULT(0);
  348.     if (regs.r_ax < MAXOPEN)
  349.       openpsp[regs.r_ax]=iobuf->process_id;
  350.     *(int *) iobuf->data=regs.r_ax;
  351.     *(int *) (iobuf->data+2)=_chmod(iobuf->data+2, 0);
  352.     regs.r_bx=*(int *) iobuf->data;   /* get file date/time      */
  353.     regs.r_ax=0x5700;                 /* assume this never fails */
  354.     intr(0x21, ®s);
  355.     *(int *) (iobuf->data+ 4) = regs.r_cx;
  356.     *(int *) (iobuf->data+ 6) = regs.r_dx;
  357.     regs.r_bx=*(int *) iobuf->data;   /* get file size           */
  358.     regs.r_cx=regs.r_dx=0;            /* assume this never fails */
  359.     regs.r_ax=0x4202;
  360.     intr(0x21, ®s);
  361.     if (regs.r_flags & 0x01)
  362.       regs.r_dx=regs.r_ax=0;
  363.     *(int *) (iobuf->data+ 8) = regs.r_ax;
  364.     *(int *) (iobuf->data+10) = regs.r_dx;
  365.     iobuf->length = 12;
  366.   }
  367. }
  368.  
  369. /*
  370.   create file
  371.     WORD   : create mode
  372.     ASCIIz : filename
  373.   return
  374.     WORD   : file handle
  375.     WORD   : file attribute
  376.     WORD   : file time
  377.     WORD   : file date
  378.     DWORD  : file length
  379. */
  380. LOCAL void svr_createfile(XMITBUF *iobuf)
  381. {
  382.   struct REGPACK regs;
  383.  
  384.   regs.r_ax=0x3c00;
  385.   regs.r_cx=*(int *) iobuf->data;
  386.   regs.r_dx=FP_OFF(iobuf->data)+2;
  387.   regs.r_ds=FP_SEG(iobuf->data);
  388.   intr(0x21, ®s);
  389.   if (regs.r_flags & 0x01) {
  390.     SETRESULT(regs.r_ax);
  391.   } else {
  392.     SETRESULT(0);
  393.     if (regs.r_ax < MAXOPEN)
  394.       openpsp[iobuf->process_id]=regs.r_ax;
  395.     *(int *) iobuf->data=regs.r_ax;
  396.     *(int *) (iobuf->data+2)=_chmod(iobuf->data+2, 0);
  397.     regs.r_bx=*(int *) iobuf->data;   /* get file date/time      */
  398.     regs.r_ax=0x5700;                 /* assume this never fails */
  399.     intr(0x21, ®s);
  400.     *(int *) (iobuf->data+ 4) = regs.r_cx;
  401.     *(int *) (iobuf->data+ 6) = regs.r_dx;
  402.     regs.r_bx=*(int *) iobuf->data;   /* get file size           */
  403.     regs.r_cx=regs.r_dx=0;            /* assume this never fails */
  404.     regs.r_ax=0x4202;
  405.     intr(0x21, ®s);
  406.     if (regs.r_flags & 0x01)
  407.       regs.r_dx=regs.r_ax=0;
  408.     *(int *) (iobuf->data+ 8) = regs.r_ax;
  409.     *(int *) (iobuf->data+10) = regs.r_dx;
  410.     iobuf->length = 12;
  411.   }
  412. }
  413.  
  414. /*
  415.   find first data block
  416.     WORD   : attrib
  417.     ASCIIz : path
  418.   result:
  419.     struct ffblk
  420. */
  421. LOCAL void svr_findfirst(XMITBUF *iobuf)
  422. {
  423.   struct ffblk ffblk;
  424.  
  425.   if (findfirst(iobuf->data+2, &ffblk, *(int *) iobuf->data)) {
  426.     SETRESULT(_doserrno);
  427.   } else
  428.     SETRESULT(0);
  429.   memcpy(iobuf->data, &ffblk, sizeof(ffblk));
  430.   iobuf->length=sizeof(ffblk);
  431. }
  432.  
  433. /*
  434.   find next data block
  435.     struct ffblk ffblk (from findfirst())
  436.   result:
  437.     struct ffblk
  438. */
  439. LOCAL void svr_findnext(XMITBUF *iobuf)
  440. {
  441.   if (findnext((struct ffblk *) iobuf->data)) {
  442.     SETRESULT(_doserrno);
  443.   } else
  444.     SETRESULT(0);
  445.   iobuf->length=sizeof(struct ffblk);
  446. }
  447.  
  448. void CloseAll(unsigned psp)
  449. {
  450.   int ii;
  451.  
  452.   for (ii=0; ii < MAXOPEN; ii++)
  453.     if (openpsp[ii] && (!psp || (openpsp[ii] == psp))) {
  454.       openpsp[ii]=0;
  455.       close(ii);
  456.     }
  457. }
  458.  
  459. LOCAL void svr_closeall(XMITBUF *iobuf)
  460. {
  461.   CloseAll(iobuf->process_id);
  462.   SETRESULT(0);
  463. }
  464.  
  465. /*
  466.   extended file open
  467.     WORD   : action
  468.     WORD   : open mode
  469.     WORD   : create attribute
  470.     ASCIIz : filename
  471.   return
  472.     WORD   : handle
  473.     WORD   : status (0 = opened, 1 = created, 2 = replaced)
  474.     WORD   : file time
  475.     WORD   : file date
  476.     DWORD  : file length
  477. */
  478. LOCAL void svr_extopen(XMITBUF *iobuf)
  479. {
  480.   struct REGPACK regs;
  481.  
  482.   regs.r_ax=0x6c00;
  483.   regs.r_bx=*(int *) (iobuf->data+2);
  484.   regs.r_cx=*(int *) (iobuf->data+4) & 0xff;
  485.   regs.r_dx=*(int *) (iobuf->data);
  486.   regs.r_ds=FP_SEG(iobuf->data);
  487.   regs.r_si=FP_OFF(iobuf->data)+6;
  488.   intr(0x21, ®s);
  489.   if (regs.r_flags & 0x01) {
  490.     SETRESULT(regs.r_ax);
  491.   } else {
  492.     SETRESULT(0);
  493.     if (regs.r_ax < MAXOPEN)
  494.       openpsp[regs.r_ax]=iobuf->process_id;
  495.     *(int *) iobuf->data=regs.r_ax;
  496.     *(int *) (iobuf->data+2) = regs.r_cx;
  497.     regs.r_bx=*(int *) iobuf->data;   /* get file date/time      */
  498.     regs.r_ax=0x5700;                 /* assume this never fails */
  499.     intr(0x21, ®s);
  500.     *(int *) (iobuf->data+ 4) = regs.r_cx;
  501.     *(int *) (iobuf->data+ 6) = regs.r_dx;
  502.     regs.r_bx=*(int *) iobuf->data;   /* get file size           */
  503.     regs.r_cx=regs.r_dx=0;            /* assume this never fails */
  504.     regs.r_ax=0x4202;
  505.     intr(0x21, ®s);
  506.     if (regs.r_flags & 0x01)
  507.       regs.r_dx=regs.r_ax=0;
  508.     *(int *) (iobuf->data+ 8) = regs.r_ax;
  509.     *(int *) (iobuf->data+10) = regs.r_dx;
  510.     iobuf->length = 12;
  511.   }
  512. }
  513.  
  514. /*
  515.   output to port
  516.     BYTE   : port #
  517.                 0..   2 = lpt #
  518.              0x80..0x83 = com #
  519.     BYTE   : function (0..2 for lpt, 0..3 for com)
  520.     BYTE   : character
  521.     BYTE   :   unused
  522.   return
  523.     BYTE   : status (modem status for com)
  524.     BYTE   : status (port status for com, ignored for lpt)
  525. */
  526. LOCAL void svr_portout(XMITBUF *iobuf)
  527. {
  528.   struct REGPACK regs;
  529.  
  530.   regs.r_dx=*(WORD *) iobuf->data;
  531.   regs.r_ax=*(WORD *) (iobuf->data+2);
  532.   if (regs.r_dx & 0x80) {
  533.     regs.r_dx &= 0x7f;
  534.     intr(0x14, ®s);
  535.   } else
  536.     intr(0x17, ®s);
  537.   SETRESULT(regs.r_ax);
  538. }
  539.  
  540. LOCAL struct {
  541.   void (*fn)(XMITBUF *iobuf);
  542. } svrTable[] = {
  543.                   svr_rmdir,
  544.                   svr_mkdir,
  545.                   svr_chdir,
  546.                   svr_closefile,
  547.                   svr_commitfile,
  548.                   svr_readfile,
  549.                   svr_writefile,
  550.                   svr_lockfile,
  551.                   svr_unlockfile,
  552.                   svr_getspace,
  553.                   svr_setattr,
  554.                   svr_getattr,
  555.                   svr_renamefile,
  556.                   svr_deletefile,
  557.                   svr_openfile,
  558.                   svr_createfile,
  559.                   svr_findfirst,
  560.                   svr_findnext,
  561.                   svr_closeall,
  562.                   svr_extopen,
  563.                   svr_portout
  564.                 };
  565.  
  566. /*
  567.   shutdown server and free memory
  568. */
  569. LOCAL void uninit(void)
  570. {
  571.   if (lcl_SDA) {
  572.     svr0_shutdown();
  573.     my_free(lcl_SDA);
  574.     my_free(lcl_CDS);
  575.     my_free(iobuf);
  576.     lcl_SDA=0;
  577.   }
  578. }
  579.  
  580. /*
  581.   return 0 if OK, else fail code
  582. */
  583. int InitServer(int intno)
  584. {
  585.   struct REGPACK regs;
  586.   BYTE *LOL; /* list of lists       */
  587.  
  588.   regs.r_ax=0x5d06;
  589.   intr(0x21, ®s);
  590.   SDA=MK_FP(regs.r_ds, regs.r_si);
  591.   SDA_maxsize=regs.r_cx;
  592.   SDA_minsize=regs.r_dx;
  593.   SDA_DOSBUSY = (void *) (SDA+1);
  594.  
  595.   /*
  596.     init lcl_SDA (for SERVER)
  597.   */
  598.   regs.r_ax=0x5200;
  599.   intr(0x21, ®s);
  600.   LOL=MK_FP(regs.r_es, regs.r_bx);
  601.  
  602.   CDS_base=*(void **) (LOL+0x16);
  603.   CDS_ct=*(BYTE *) (LOL + 0x21);
  604.   CDS_EntrySize=(_osmajor == 0x03) ? 0x51 : 0x58;
  605.   CDS_TotalSize=CDS_ct * CDS_EntrySize;
  606.  
  607.   if (background) {
  608.     lcl_SDA=my_malloc(SDA_maxsize);
  609.     if (!lcl_SDA)
  610.       return 1;
  611.     memcpy(lcl_SDA, SDA, SDA_maxsize);
  612.     lcl_CDS=my_malloc(CDS_TotalSize);
  613.     if (!lcl_CDS) {
  614.       my_free(lcl_SDA);
  615.       return 1;
  616.     }
  617.     memcpy(lcl_CDS, CDS_base, CDS_TotalSize);
  618.   }
  619.  
  620.   iobufptr=iobuf=my_malloc(sizeof(*iobuf)+datasize);
  621.  
  622.   if (!iobuf) {
  623.     if (lcl_SDA)
  624.       my_free(lcl_SDA);
  625.     if (lcl_CDS)
  626.       my_free(lcl_CDS);
  627.     if (iobuf)
  628.       my_free(iobuf);
  629.     return 1;
  630.   }
  631.   svr0_init(intno);
  632.   return 0;
  633. }
  634.  
  635. LOCAL long dispatchct=0;
  636. LOCAL int  dispatchfn=0;
  637.  
  638. void ServerDispatch(void)
  639. {
  640.   void interrupt (*oldint1b)();
  641.   void interrupt (*oldint23)();
  642.   void interrupt (*oldint24)();
  643.  
  644.   dispatchct++;
  645.  
  646.   oldint1b=getvect(0x1b);
  647.   setvect(0x1b, svr0_int1b);
  648.  
  649.   oldint23=getvect(0x23);     /* swap ctl-break address */
  650.   setvect(0x23, svr0_int23);  /* (ignore ctl-break) */
  651.  
  652.   oldint24=getvect(0x24);     /* swap critical error question */
  653.   setvect(0x24, svr0_int24);  /* return FAIL always */
  654.  
  655.   IFS_stat.inserver++;
  656.   if ((iobufptr->cmd >= 0) &&            /* check for valid function    */
  657.       (iobufptr->cmd < IFS_ENDOFLIST) &&
  658.        svrTable[iobufptr->cmd].fn) {
  659.     dispatchfn=iobufptr->cmd;
  660.     svrTable[iobufptr->cmd].fn(iobufptr);        /* call if valid */
  661.   } else {
  662.     SETRESULT(0x05);                  /* otherwise result is invalid */
  663.   }
  664.  
  665.   iobufptr->packetID[0]='L';
  666.   iobufptr->packetID[1]='Y';
  667.   iobufptr->length += sizeof(*iobufptr);
  668.   iobufptr->notlength = ~iobufptr->length;
  669.   iobufptr->crc32 = 0;
  670.   iobufptr->crc32=crc32(0, iobufptr, iobufptr->length);
  671.   if (background)
  672.     CommIO_Transmit(iobufptr, iobufptr->length);
  673.   else
  674.     CommIO_TransmitLoop(iobufptr, iobufptr->length);
  675.   setvect(0x1b, oldint1b);
  676.   setvect(0x23, oldint23);
  677.   setvect(0x24, oldint24);
  678.   svr0_ResetDispatchFlag();           /* tell the world         */
  679.   state=0;                            /* ready for next request */
  680. }
  681.  
  682. void _Recieve(void)
  683. {
  684.   LOCAL char *ptr=0;
  685.   LOCAL int   rcvd=0;
  686.   LOCAL int   last=0;
  687.   int key;
  688.  
  689.   if (!background)
  690.     key=CommIO_WaitByteLoop(36);
  691.   else
  692.     key=-1;
  693.   while ((state != 3) && (CommIO_RecievePending() || (key >= 0))) {
  694.  
  695.     if (background)
  696.       key=CommIO_GetByte();
  697.  
  698.     switch (state) {
  699.       case 0: /* no current state, wait for 'K' */
  700.         if (key == 'K')
  701.           state++;
  702.         break;
  703.       case 1: /* 'K' found, if next character is 'Y', increase state */
  704.         if ((last == 'K') && (key == 'Y')) {
  705.           ptr=(char *) iobufptr;
  706.           iobufptr->length=0;
  707.           *(ptr++)=last;
  708.           *(ptr++)=key;
  709.           rcvd=2;
  710.           state++;
  711.         } else /* otherwise reset state */
  712.           state=0;
  713.         break;
  714.       case 2:
  715.         *(ptr++)=key;
  716.         if (++rcvd == sizeof(*iobufptr)) {
  717.           if ((iobufptr->length != ~iobufptr->notlength)
  718.                || (iobufptr->length > datasize+sizeof(*iobufptr))) {
  719.             CommIO_FlushBuffer();
  720.             state=0;
  721.             IFS_stat.lenfail++;
  722.           }
  723.         }
  724.         if (rcvd == iobufptr->length) {
  725.           DWORD ocrc=iobufptr->crc32;
  726.           iobufptr->crc32=0;
  727.           if (crc32(0, iobufptr, iobufptr->length) != ocrc) {
  728.             CommIO_FlushBuffer();
  729.             IFS_stat.crcfail++;
  730.             state=0;
  731.           } else {
  732.             IFS_stat.valid += iobufptr->length;
  733.             state++;
  734.             svr0_SetDispatchFlag();
  735.           }
  736.         }
  737.     }
  738.     last=key;
  739.     if (!background && (state != 3))
  740.       key=CommIO_WaitByteLoop(36);
  741.     else
  742.       key=-1;
  743.   }
  744. }
  745.  
  746. LOCAL char *options[]={"/speed=",
  747.                "/com1",
  748.                "/com2",
  749.                "/com3",
  750.                "/com4",
  751.                "/irq=",
  752.                "/port=",
  753.                "/remove",
  754.                "/nobackground",
  755.                "/intno=",
  756.                "/reset",
  757.                NULL};
  758.  
  759. void main(int argc, char **argv)
  760. {
  761.   char *ptr;
  762.   long  speed=19200;
  763.   int   com=-1,
  764.         irq=-1,
  765.         port=-1,
  766.         intno=FindUnusedInt();
  767.   BOOL  removeflag=FALSE,
  768.         resetflag=FALSE;
  769.   int   opt, RIFS=FindRIFS();
  770.   {
  771.     /*
  772.       1st lose the environment
  773.     */
  774.     unsigned seg=*(WORD *) MK_FP(_psp, 0x2c);
  775.     freemem(seg);
  776.   }
  777.   ArgInit(argc, argv);
  778.   while ((opt=GetOption(options)) != -1) {
  779.     switch (opt) {
  780.       case 0:
  781.         speed=strtol(GetArg(), &ptr, 0x0a);
  782.         if (speed == 0)
  783.           ArgError("speed out of range [2..115200]");
  784.         if (115200L % speed)
  785.           speed=115200/(115200/speed+1);
  786.         break;
  787.       case 1:
  788.       case 2:
  789.       case 3:
  790.       case 4:
  791.         com=opt;
  792.         break;
  793.       case 5:
  794.         irq=strtol(GetArg(), &ptr, 0x10);
  795.         if ((irq < 0) || (irq > 0x0f))
  796.           ArgError("IRQ out of range [0..0f]");
  797.         break;
  798.       case 6:
  799.         port=strtol(GetArg(), &ptr, 0x10);
  800.         break;
  801.       case 7:
  802.         removeflag=TRUE;
  803.         break;
  804.       case 8:
  805.         background=FALSE;
  806.         break;
  807.       case 9:
  808.         intno=strtol(GetArg(), &ptr, 0x10);
  809.         break;
  810.       case 10:
  811.         resetflag=TRUE;
  812.         break;
  813.     }
  814.   }
  815.   if (removeflag || resetflag) {
  816.     struct REGPACK regs;
  817.  
  818.     if (RIFS) {
  819.       regs.r_ax=RSERVER_QUERY;
  820.       intr(RIFS, ®s);
  821.     }
  822.     if (!RIFS || (regs.r_ax != 0x4321)) {
  823.       printf("RSERVER not found\n");
  824.       exit(1);
  825.     } else {
  826.       regs.r_ax=(removeflag) ? RSERVER_UNLOAD : RSERVER_RESET;
  827.       intr(RIFS, ®s);
  828.       printf("RSERVER %s\n", removeflag ? "removed from memory" : "reset");
  829.       exit(0);
  830.     }
  831.   } else if (RIFS) {
  832.     struct REGPACK regs;
  833.     regs.r_ax=RSERVER_QUERY;
  834.     intr(RIFS, ®s);
  835.     if (regs.r_ax == 0x4321) {
  836.       printf("RSERVER already loaded\n");
  837.       exit(1);
  838.     }
  839.     regs.r_ax=RCLIENT_QUERY;
  840.     intr(RIFS, ®s);
  841.     if (regs.r_ax == 0x1234) {
  842.       printf("RCLIENT already loaded\n");
  843.       exit(1);
  844.     }
  845.   }
  846.   if ((com < 0) && ((irq < 0) || (port < 0))) {
  847.     for (com=0; com < 4; com++)
  848.       if (*(WORD *) (MK_FP(0x40, 2*com)))
  849.         break;
  850.     if (com == 4)
  851.       ArgError("cannot find available com port");
  852.     else
  853.       com++;
  854.   }
  855.   if (!intno)
  856.     ArgError("cannot find unused user interrupt");
  857.   if (background && ((_osmajor != 0x03) && (_osmajor < 0x05))) {
  858.     fprintf(stderr, "RIFS Server Background Mode is ONLY compatable with\n"
  859.                     "DOS 3.x and DOS >= 5.x (not 4.x)\n");
  860.     exit(1);
  861.   }
  862.  
  863.   {
  864.     int res=InitServer(intno);
  865.     if (res) {
  866.       fprintf(stderr, "Error (%d) initializing server\n", res);
  867.       exit(1);
  868.     }
  869.     res = CommIO_Initialize(com, STOP_1 | WORD_8 | PARITY_NONE, speed, background ? irq : 0, port);
  870.     if (res) {
  871.       fprintf(stderr, "Error (%d) initializing serial port\n");
  872.       uninit();
  873.       exit(1);
  874.     }
  875.   }
  876.   printf("IFS server initialized on port (%d) at (%ld)\n", com, speed);
  877.   if (background) {
  878.     MCB *mcb=MK_FP(_psp-1, 0);
  879.     keep(0, mcb->size);
  880.   } else {
  881.     for ( ; ; ) {
  882.       _Recieve();
  883.       if (state == 3)
  884.         ServerDispatch();
  885.       if (kbhit() && getch()  == 27)
  886.         break;
  887.       putch('*');
  888.     }
  889.   }
  890.   CommIO_shutdown();
  891.   CloseAll(0);
  892.   uninit();
  893. }
  894.  
  895. /*
  896.   user interrupt for communicating with the server
  897. */
  898. void UserInt(INTREGS *regs)
  899. {
  900.   regs->flags &= ~0x01;
  901.   switch (regs->ax) {
  902.     case RSERVER_QUERY:
  903.       regs->ax=0x4321;
  904.       break;
  905.     case RSERVER_GETSTAT:
  906.       regs->es=FP_SEG(&IFS_stat);
  907.       regs->bx=FP_OFF(&IFS_stat);
  908.       IFS_stat.totalsent=total_sent;
  909.       IFS_stat.totalrcvd=total_rcvd;
  910.       IFS_stat.stackused=svr0_GetStackUsed();
  911.       IFS_stat.openpsp=openpsp;
  912.       IFS_stat.openhandle=MK_FP(_psp, 0x18);
  913.       break;
  914.     case RSERVER_UNLOAD:
  915.       SwapDOS();
  916.       CloseAll(0);
  917.       SwapDOS();
  918.       CommIO_shutdown();
  919.       uninit();
  920.       freemem(_psp);
  921.       break;
  922.     case RSERVER_RESET: /* close all open files */
  923.       SwapDOS();
  924.       CloseAll(0);
  925.       SwapDOS();
  926.       break;
  927.     default:
  928.       regs->flags |= 0x01;
  929.   }
  930. }
  931.